{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "eb58189e-0daf-4463-b572-bd86b3049ff9",
   "metadata": {},
   "source": [
    "# Quantum Volume\n",
    "\n",
    "Quantum volume is a measurement of the error amount characterizing a chosen quantum hardware. The quantum volume is a result of running a circuit based on principles of randomness and statistical analysis, which provides a single number to compare between different hardware backends.\n",
    "\n",
    "The scheme of the quantum volume [1]:\n",
    "1. For a number of qubits $n$, a circuit is made of the $n$ quantum layer.\n",
    "2. Each layer consists of a unitary operation between pairs of $n$ qubits. The pairs are chosen at random. If $n$ is odd, one of them does not have an operation.\n",
    "3. The unitary operation between each pair is the Haar random matrix; i.e., SU(4) operation containing a random complex number in such a manner that the probability of measuring a quantum state is kept with uniform distribution.\n",
    "4. A single circuit of $n$ qubits is measured and the heavy output probability (i.e., the probability of measuring the states above the median value) is calculated. Due to the nature of the distribution of random complex number, one can evaluate that for an ideal case (no noises), the heavy output probability should be ~0.85. For assessment of the quantum volume, the demand subsides to the following inequality: (1) P{heavy_outputs} >= 2/3 .\n",
    "5. For a given output, to get the quantum volume, repeat Items 1-4 for an increasing number of qubits until the inequality described in Item 4 does not hold. To ensure it, the circuits are created many times and the average and standard deviation are taken into account.\n",
    "6. The quantum volume is 2 to the power of the number of qubits, such that they pass inequality (1) as per the procedure described in Items 1-5.\n",
    "\n",
    "The heavy output probability is a good measurement of the quality of the circuit, as noise reduces the probabilities of uniform distribution. While this is so, consider that there are many components to the results of the procedure\u2014not only the hardware noises, but also the connectivity map, the quality of the transpilation, and even the quantum software that translates the circuit into basis gates for the hardware, thus contributing to the circuit depth.\n",
    "\n",
    "This demonstration shows the code for implementing the steps to calculate the quantum volume using the Classiq platform and an example of such calculations for several quantum simulators and hardware backends."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d9973f53-8fd9-4cb1-a285-11f9676ff3e1",
   "metadata": {},
   "source": [
    "## Step 1: Create a Haar Random Unitary Matrix\n",
    "\n",
    "Create a function, generating a (n,n) sized Haar random unitary matrix [2]. This matrix contains a random complex number that is distributed evenly in the $2^n$ space of quantum states. The Haar distribution indicates how to weight the elements of $\ud835\udc48(\ud835\udc41)$ such that uniform distribution occurs in the parameter space."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "4a618997-d7de-4edb-82b5-c8f40036f57c",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-05-07T15:33:52.183401Z",
     "iopub.status.busy": "2024-05-07T15:33:52.182744Z",
     "iopub.status.idle": "2024-05-07T15:33:52.835437Z",
     "shell.execute_reply": "2024-05-07T15:33:52.834589Z"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "from numpy.linalg import qr\n",
    "from scipy.stats import unitary_group\n",
    "\n",
    "\n",
    "def haar(n):\n",
    "    u1 = unitary_group.rvs(n)\n",
    "    u2 = unitary_group.rvs(n)\n",
    "    Z = u1 + 1j * u2\n",
    "\n",
    "    Q, R = qr(Z)\n",
    "\n",
    "    Lambda = np.diag([R[i, i] / np.abs(R[i, i]) for i in range(n)])\n",
    "\n",
    "    return np.dot(Q, Lambda)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4a347727-e521-4767-ba7e-dccf0d7d76bc",
   "metadata": {},
   "source": [
    "## Step 2: Create a Quantum Volume Circuit\n",
    "\n",
    "The `qv_model` function creates the quantum volume model for a given $N$ number of qubits. For $N$ qubits, the circuit must include $N$ quantum volume layers. The layers are built using the `qv_layer` function, which creates random pairing between the $N$ qubits. (For an odd number, a randomly chosen qubit is not operational). Between each pair, a unitary gate operates, consisting of a Haar random unitary matrix of size 4."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "a48dcb13-5726-46ad-86a0-357d87f23d27",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-05-07T15:33:52.841958Z",
     "iopub.status.busy": "2024-05-07T15:33:52.840652Z",
     "iopub.status.idle": "2024-05-07T15:33:55.512469Z",
     "shell.execute_reply": "2024-05-07T15:33:55.511779Z"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "import math\n",
    "import random\n",
    "\n",
    "from classiq.qmod import (\n",
    "    CArray,\n",
    "    CReal,\n",
    "    Output,\n",
    "    QArray,\n",
    "    QBit,\n",
    "    allocate,\n",
    "    bind,\n",
    "    create_model,\n",
    "    qfunc,\n",
    "    unitary,\n",
    ")\n",
    "\n",
    "\n",
    "@qfunc\n",
    "def apply_2qbit_unitary(unitary_params: CArray[CArray[CReal]], x: QBit, y: QBit):\n",
    "    joined = QArray[QBit](\"joined\")\n",
    "    bind([x, y], joined)\n",
    "    unitary(unitary_params, joined)\n",
    "    bind(joined, [x, y])\n",
    "\n",
    "\n",
    "# We will use flat-python in order to generate the random unitaries.\n",
    "# That is why you don't see the @qfunc decorator here\n",
    "def qv_layer(target: QArray[QBit], N):\n",
    "    # Step 1: start with a shuffle of the qubits\n",
    "    qubit_list = list(range(N))\n",
    "    random.shuffle(qubit_list)\n",
    "\n",
    "    for idx in range(math.floor(N / 2)):\n",
    "        # Step 2: Isolate the qubit pairs for the layers\n",
    "        a = qubit_list[idx]\n",
    "        b = qubit_list[math.floor(N / 2) + idx]\n",
    "\n",
    "        # Step 3: Generate the random matrix (this needs to change for the random matrix when possible)\n",
    "        gate_matrix = haar(4).tolist()\n",
    "        apply_2qbit_unitary(gate_matrix, target[a], target[b])\n",
    "\n",
    "\n",
    "def qv_model(N):\n",
    "    @qfunc\n",
    "    def main(target: Output[QArray[QBit]]):\n",
    "        allocate(N, target)\n",
    "        for idx in range(N):\n",
    "            qv_layer(target, N)\n",
    "\n",
    "    return create_model(main)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7392eab8-bbc1-4170-869b-908106cd221b",
   "metadata": {},
   "source": [
    "## Step 3: Execute and Analyze\n",
    "\n",
    "\n",
    "The execution and analysis part consists of these functions:\n",
    "* `execute_qv` sends a quantum program for execution on a given quantum hardware with a specified number of shots. The function returns the results of the execution from the hardware.\n",
    "* `heavy_outputs_prob` which analyze the results from execution, and returns the heavy output probability, i.e. the probability for a single state in the space to be greater then the median value (median = \"middle\" of a sorted list of numbers).\n",
    "\n",
    "The function`round_significant` rounds a number for one significant figure."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "b5c9b1d5-9a52-4305-be41-299093013e9d",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-05-07T15:33:55.515798Z",
     "iopub.status.busy": "2024-05-07T15:33:55.514933Z",
     "iopub.status.idle": "2024-05-07T15:33:55.519185Z",
     "shell.execute_reply": "2024-05-07T15:33:55.518581Z"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "from classiq import execute, set_quantum_program_execution_preferences\n",
    "from classiq.execution import (\n",
    "    AzureBackendPreferences,\n",
    "    ClassiqBackendPreferences,\n",
    "    ClassiqSimulatorBackendNames,\n",
    "    ExecutionPreferences,\n",
    ")\n",
    "\n",
    "\n",
    "def execute_qv(qprog, num_shots, preferences):\n",
    "    qprog = set_quantum_program_execution_preferences(\n",
    "        qprog,\n",
    "        ExecutionPreferences(num_shots=num_shots, backend_preferences=preferences),\n",
    "    )\n",
    "    results = execute(qprog).result()\n",
    "    return results[0].value"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "4c7571be-115c-4f7b-8fd5-cd6bf23eb895",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-05-07T15:33:55.521461Z",
     "iopub.status.busy": "2024-05-07T15:33:55.521157Z",
     "iopub.status.idle": "2024-05-07T15:33:55.524754Z",
     "shell.execute_reply": "2024-05-07T15:33:55.524182Z"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "def heavy_outputs_prob(results):\n",
    "    d = list(results.counts.values())\n",
    "    med = np.median(d)\n",
    "    heavy_outputs_prob = 0\n",
    "    # print(med)\n",
    "    for count, item in enumerate(d):\n",
    "        if item >= med:\n",
    "            heavy_outputs_prob = heavy_outputs_prob + item\n",
    "    return heavy_outputs_prob"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "d3879815-8515-46dc-a154-3d317be4cfb6",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-05-07T15:33:55.527621Z",
     "iopub.status.busy": "2024-05-07T15:33:55.527453Z",
     "iopub.status.idle": "2024-05-07T15:33:55.530478Z",
     "shell.execute_reply": "2024-05-07T15:33:55.529876Z"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "from math import floor, log10\n",
    "\n",
    "\n",
    "def round_significant(x):\n",
    "    return round(x, -int(floor(log10(abs(x)))))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "76638dca-b6fe-4721-99f1-956a617bdc27",
   "metadata": {},
   "source": [
    "## Step 4: Find the Quantum Volume Algorithm\n",
    "\n",
    "Using the previously defined functions, `find_qv` finds the quantum volume value, for defined parameters including hardware definitions.\n",
    "The `find_qv` function, send for each number of qubits defined (between `min_qubit` and `max_qubits`) the value of heavy output probability. This is repeated `num_trials` times. Then, the heavy output probability is averaged, and the standard deviation is calculated. If the number of qubits chosen for the circuit is less than the number of qubits in the chosen hardware, the qubits will be randomly picked for run according to the rules of the hardware provider.\n",
    "\n",
    "The quantum volume qubits number is defined as the larger number of qubits for which the heavy output probability, decrease by two sigma (2 times the standard deviation), is more or equal to 2/3. The quantum volume will be 2 to the power the number of quantum volume qubits.\n",
    "\n",
    "One must note, that if the result given for the log2 of the quantum volume is the same as the chosen `max_qubits`, there is a possibility that the quantum volume is greater then found by the function, and we recommend to run the program for a greater span."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "c8b7af0a-7560-4bfd-9437-52c9d858d807",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-05-07T15:33:55.532678Z",
     "iopub.status.busy": "2024-05-07T15:33:55.532492Z",
     "iopub.status.idle": "2024-05-07T15:33:55.544577Z",
     "shell.execute_reply": "2024-05-07T15:33:55.543988Z"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "from tqdm import tqdm\n",
    "\n",
    "from classiq import synthesize\n",
    "\n",
    "\n",
    "def find_qv(num_trials, num_shots, min_qubits, max_qubits, preferences):\n",
    "    ### initialization\n",
    "    qubit_num = range(min_qubits, max_qubits + 1)\n",
    "    heavy_list = np.zeros(max_qubits - min_qubits + 1)\n",
    "    std_list = np.zeros(max_qubits - min_qubits + 1)\n",
    "    qubit_v = 0\n",
    "\n",
    "    ### calculate the heavy outputs for each number of qubits\n",
    "    for num in tqdm(qubit_num):\n",
    "        heavy_outputs = 0\n",
    "        std = 0\n",
    "        heavytostd = np.zeros(num_trials)\n",
    "        for idx in tqdm(range(num_trials)):\n",
    "            model = qv_model(num)\n",
    "            qprog = synthesize(model)\n",
    "            results = execute_qv(qprog, num_shots, preferences)\n",
    "            heavy_temp = heavy_outputs_prob(results)\n",
    "            heavy_outputs = heavy_outputs + heavy_temp\n",
    "            heavytostd[idx] = heavy_temp\n",
    "        s = num - min_qubits\n",
    "        heavy_list[s] = heavy_outputs / (num_trials * num_shots)\n",
    "        temp_hl = heavy_outputs / (num_trials * num_shots)\n",
    "        std = np.std(heavytostd) / (num_trials * num_shots)\n",
    "        std_list[s] = std\n",
    "        temp_std = round_significant(std)\n",
    "        print(\n",
    "            \"for\",\n",
    "            num,\n",
    "            \"qubits the heavy outputs probability is:\",\n",
    "            temp_hl,\n",
    "            \"with\",\n",
    "            temp_std,\n",
    "            \"standard deviation\",\n",
    "        )\n",
    "\n",
    "    ### determine the quantum volume\n",
    "    for num in qubit_num:\n",
    "        s = num - min_qubits\n",
    "        heavy_is = heavy_list[s] - 2 * (std_list[s])\n",
    "        if heavy_is >= 2 / 3:\n",
    "            qubit_v = num\n",
    "        else:\n",
    "            break\n",
    "\n",
    "    qv = 2**qubit_v\n",
    "    print(\"##### The quantum volume is\", qv, \"#####\")\n",
    "\n",
    "    return qv"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6d678346-ec06-4562-85e7-79bcbaeae9e4",
   "metadata": {},
   "source": [
    "## Examples\n",
    "\n",
    "Run the code to find the quantum volume of several quantum simulators and hardwares."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fe220794-001e-4e8f-8a64-970b42148853",
   "metadata": {},
   "source": [
    "### Running with Classiq's Simulator"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "bb5a50db-567f-42ca-a5e1-3cf40208bb5e",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-05-07T15:33:55.547076Z",
     "iopub.status.busy": "2024-05-07T15:33:55.546642Z",
     "iopub.status.idle": "2024-05-07T15:36:40.116872Z",
     "shell.execute_reply": "2024-05-07T15:36:40.116152Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      "  0%|          | 0/4 [00:00<?, ?it/s]"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      "  0%|          | 0/10 [00:00<?, ?it/s]"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[A"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      " 10%|\u2588         | 1/10 [00:03<00:34,  3.81s/it]"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[A"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      " 20%|\u2588\u2588        | 2/10 [00:07<00:29,  3.63s/it]"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[A"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      " 30%|\u2588\u2588\u2588       | 3/10 [00:10<00:24,  3.57s/it]"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[A"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      " 40%|\u2588\u2588\u2588\u2588      | 4/10 [00:14<00:21,  3.58s/it]"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[A"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      " 50%|\u2588\u2588\u2588\u2588\u2588     | 5/10 [00:18<00:18,  3.62s/it]"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[A"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      " 60%|\u2588\u2588\u2588\u2588\u2588\u2588    | 6/10 [00:21<00:14,  3.63s/it]"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[A"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      " 70%|\u2588\u2588\u2588\u2588\u2588\u2588\u2588   | 7/10 [00:25<00:10,  3.63s/it]"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[A"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      " 80%|\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588  | 8/10 [00:28<00:07,  3.62s/it]"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[A"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      " 90%|\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588 | 9/10 [00:31<00:03,  3.29s/it]"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[A"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      "100%|\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588| 10/10 [00:35<00:00,  3.46s/it]"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[A"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      "100%|\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588| 10/10 [00:35<00:00,  3.54s/it]"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n",
      "\r",
      " 25%|\u2588\u2588\u258c       | 1/4 [00:35<01:46, 35.40s/it]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "for 3 qubits the heavy outputs probability is: 0.811 with 0.008 standard deviation\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      "  0%|          | 0/10 [00:00<?, ?it/s]"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[A"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      " 10%|\u2588         | 1/10 [00:03<00:32,  3.57s/it]"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[A"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      " 20%|\u2588\u2588        | 2/10 [00:07<00:28,  3.55s/it]"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[A"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      " 30%|\u2588\u2588\u2588       | 3/10 [00:10<00:25,  3.58s/it]"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[A"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      " 40%|\u2588\u2588\u2588\u2588      | 4/10 [00:15<00:23,  3.93s/it]"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[A"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      " 50%|\u2588\u2588\u2588\u2588\u2588     | 5/10 [00:19<00:20,  4.19s/it]"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[A"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      " 60%|\u2588\u2588\u2588\u2588\u2588\u2588    | 6/10 [00:23<00:16,  4.02s/it]"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[A"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      " 70%|\u2588\u2588\u2588\u2588\u2588\u2588\u2588   | 7/10 [00:27<00:11,  3.94s/it]"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[A"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      " 80%|\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588  | 8/10 [00:32<00:08,  4.19s/it]"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[A"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      " 90%|\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588 | 9/10 [00:35<00:03,  4.00s/it]"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[A"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      "100%|\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588| 10/10 [00:39<00:00,  3.85s/it]"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[A"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      "100%|\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588| 10/10 [00:39<00:00,  3.91s/it]"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n",
      "\r",
      " 50%|\u2588\u2588\u2588\u2588\u2588     | 2/4 [01:14<01:15, 37.60s/it]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "for 4 qubits the heavy outputs probability is: 0.846 with 0.004 standard deviation\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      "  0%|          | 0/10 [00:00<?, ?it/s]"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[A"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      " 10%|\u2588         | 1/10 [00:04<00:42,  4.72s/it]"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[A"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      " 20%|\u2588\u2588        | 2/10 [00:08<00:33,  4.13s/it]"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[A"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      " 30%|\u2588\u2588\u2588       | 3/10 [00:12<00:27,  3.91s/it]"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[A"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      " 40%|\u2588\u2588\u2588\u2588      | 4/10 [00:15<00:22,  3.82s/it]"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[A"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      " 50%|\u2588\u2588\u2588\u2588\u2588     | 5/10 [00:20<00:20,  4.09s/it]"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[A"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      " 60%|\u2588\u2588\u2588\u2588\u2588\u2588    | 6/10 [00:25<00:17,  4.31s/it]"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[A"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      " 70%|\u2588\u2588\u2588\u2588\u2588\u2588\u2588   | 7/10 [00:28<00:12,  4.12s/it]"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[A"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      " 80%|\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588  | 8/10 [00:33<00:08,  4.28s/it]"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[A"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      " 90%|\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588 | 9/10 [00:38<00:04,  4.39s/it]"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[A"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      "100%|\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588| 10/10 [00:41<00:00,  4.21s/it]"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[A"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      "100%|\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588| 10/10 [00:41<00:00,  4.18s/it]"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n",
      "\r",
      " 75%|\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u258c  | 3/4 [01:56<00:39, 39.54s/it]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "for 5 qubits the heavy outputs probability is: 0.835 with 0.005 standard deviation\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      "  0%|          | 0/10 [00:00<?, ?it/s]"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[A"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      " 10%|\u2588         | 1/10 [00:04<00:44,  4.90s/it]"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[A"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      " 20%|\u2588\u2588        | 2/10 [00:09<00:38,  4.84s/it]"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[A"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      " 30%|\u2588\u2588\u2588       | 3/10 [00:14<00:33,  4.85s/it]"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[A"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      " 40%|\u2588\u2588\u2588\u2588      | 4/10 [00:19<00:28,  4.80s/it]"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[A"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      " 50%|\u2588\u2588\u2588\u2588\u2588     | 5/10 [00:23<00:23,  4.76s/it]"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[A"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      " 60%|\u2588\u2588\u2588\u2588\u2588\u2588    | 6/10 [00:28<00:19,  4.77s/it]"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[A"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      " 70%|\u2588\u2588\u2588\u2588\u2588\u2588\u2588   | 7/10 [00:33<00:14,  4.76s/it]"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[A"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      " 80%|\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588  | 8/10 [00:38<00:09,  4.96s/it]"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[A"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      " 90%|\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588 | 9/10 [00:43<00:04,  4.89s/it]"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[A"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      "100%|\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588| 10/10 [00:48<00:00,  4.78s/it]"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[A"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      "100%|\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588| 10/10 [00:48<00:00,  4.82s/it]"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n",
      "\r",
      "100%|\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588| 4/4 [02:44<00:00, 42.95s/it]"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      "100%|\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588| 4/4 [02:44<00:00, 41.14s/it]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "for 6 qubits the heavy outputs probability is: 0.861 with 0.006 standard deviation\n",
      "##### The quantum volume is 64 #####\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    }
   ],
   "source": [
    "num_trials = 10  # number of times to run the QV circuit for each number of qubits. Best: 200 or more\n",
    "num_shots = 100  # number of runs for each execution. Best: 1000 or more\n",
    "preferences = ClassiqBackendPreferences(\n",
    "    backend_name=ClassiqSimulatorBackendNames.SIMULATOR\n",
    ")\n",
    "min_qubits = 3\n",
    "max_qubits = 6\n",
    "\n",
    "qv = find_qv(num_trials, num_shots, min_qubits, max_qubits, preferences)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "162c4f95-3fe8-47ce-818d-df961d9d9ff0",
   "metadata": {},
   "source": [
    "Since this is a simulator with no errors, we expect the heavy output probability for any number of qubits to be approximately 0.85"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f01490fa-6624-430d-b56b-e5c30b0715b2",
   "metadata": {},
   "source": [
    "### Running with Rigetti Aspen M-3"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "732226b4-ff31-4a56-97bf-581c59bfdffb",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-05-07T15:36:40.120637Z",
     "iopub.status.busy": "2024-05-07T15:36:40.120132Z",
     "iopub.status.idle": "2024-05-07T15:36:40.124737Z",
     "shell.execute_reply": "2024-05-07T15:36:40.124180Z"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "num_trials = 10  # number of times to run the QV circuit for each number of qubits\n",
    "num_shots = 3  # number of runs for each execution\n",
    "preferences = AzureBackendPreferences(backend_name=\"Rigetti.Qpu.Aspen-M-3\")\n",
    "min_qubits = 2\n",
    "max_qubits = 3\n",
    "\n",
    "# qv = find_qv_trials, num_(numshots, min_qubits, max_qubits, preferences)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3400fa07-4329-42b8-b580-46222b1e6762",
   "metadata": {},
   "source": [
    "### Running with IBM Machines"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5ba00431-8658-46ac-8fe5-ac6f15977a17",
   "metadata": {},
   "source": [
    "Try to run a few IBM machines: ibmq_lima with reported quantum volume of 8; ibmq_quito with reported quantum volume of 16; and ibmq_manila with reported quantum volume of 32 [3]."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "46ba9fe2-292d-4912-a3d8-9681fbff3e88",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-05-07T15:36:40.127792Z",
     "iopub.status.busy": "2024-05-07T15:36:40.127402Z",
     "iopub.status.idle": "2024-05-07T15:36:40.132509Z",
     "shell.execute_reply": "2024-05-07T15:36:40.131950Z"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "from classiq.execution import IBMBackendPreferences, IBMBackendProvider\n",
    "\n",
    "ibm_provider = IBMBackendProvider()\n",
    "\n",
    "preferences = IBMBackendPreferences(\n",
    "    backend_name=\"ibmq_lima\",\n",
    "    access_token=\"insert_token_number\",\n",
    "    provider=ibm_provider,\n",
    ")\n",
    "\n",
    "num_trials = 5  # number of times to run the QV circuit for each number of qubits\n",
    "num_shots = 10  # number of runs for each execution\n",
    "min_qubits = 2\n",
    "max_qubits = 4\n",
    "\n",
    "# qv = find_qv(num_trials, num_shots, min_qubits, max_qubits, preferences)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "93838767-ec86-4790-b76e-ff6c2d17b21f",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-05-07T15:36:40.136247Z",
     "iopub.status.busy": "2024-05-07T15:36:40.135152Z",
     "iopub.status.idle": "2024-05-07T15:36:40.140573Z",
     "shell.execute_reply": "2024-05-07T15:36:40.139877Z"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "from classiq.execution import IBMBackendPreferences, IBMBackendProvider\n",
    "\n",
    "ibm_provider = IBMBackendProvider()\n",
    "\n",
    "preferences = IBMBackendPreferences(\n",
    "    backend_name=\"ibmq_quito\",\n",
    "    access_token=\"insert_token_number\",\n",
    "    provider=ibm_provider,\n",
    ")\n",
    "\n",
    "num_trials = 1  # number of times to run the QV circuit for each number of qubits\n",
    "num_shots = 10  # number of runs for each execution\n",
    "min_qubits = 2\n",
    "max_qubits = 3\n",
    "\n",
    "# qv = find_qv(num_trials, num_shots, min_qubits, max_qubits, preferences)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "fd035d07-2d2e-4df0-8f3c-5e91824718d3",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-05-07T15:36:40.145996Z",
     "iopub.status.busy": "2024-05-07T15:36:40.144928Z",
     "iopub.status.idle": "2024-05-07T15:36:40.150189Z",
     "shell.execute_reply": "2024-05-07T15:36:40.149637Z"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "from classiq.execution import IBMBackendPreferences, IBMBackendProvider\n",
    "\n",
    "ibm_provider = IBMBackendProvider()\n",
    "\n",
    "preferences = IBMBackendPreferences(\n",
    "    backend_name=\"ibmq_manila\",\n",
    "    access_token=\"insert_token_number\",\n",
    "    provider=ibm_provider,\n",
    ")\n",
    "\n",
    "num_trials = 1  # number of times to run the QV circuit for each number of qubits\n",
    "num_shots = 10  # number of runs for each execution\n",
    "min_qubits = 2\n",
    "max_qubits = 3\n",
    "\n",
    "# qv = find_qv(num_trials, num_shots, min_qubits, max_qubits, preferences)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0141348c-d63f-46c6-90e2-ae6b11308947",
   "metadata": {},
   "source": [
    "## References\n",
    "\n",
    "[1] https://arxiv.org/pdf/1811.12926.pdf.\n",
    "\n",
    "[2] How to generate a random unitary matrix by Maris Ozols: http://home.lu.lv/~sd20008/papers/essays/Random%20unitary%20[paper].pdf.\n",
    "\n",
    "[3] Computer resources from the official IBM website: https://quantum-computing.ibm.com/services/resources?tab=yours.\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
